package com.sky.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisDataConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.exception.BaseException;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.DishMapper;
import com.sky.po.DishFlavorPO;
import com.sky.po.DishPO;
import com.sky.po.SetmealDishPO;
import com.sky.repository.DishRepository;
import com.sky.repository.SetmealDishRepository;
import com.sky.result.PageResult;
import com.sky.service.DishFlavorService;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * @Content: 菜品管理
 * @Author: Asen
 * @Date: 2023/9/1 13:57
 */
@Slf4j
@Service
public class DishServiceImpl implements DishService {
    @Autowired
    private DishRepository dishRepository;
    @Autowired
    private SetmealDishRepository setmealDishRepository;
    @Autowired
    @Lazy
    private DishFlavorService dishFlavorService;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 新增菜品和对应的口味
     * @param source
     * @return
     */
    @Override
    @Transactional
    public Boolean saveWithFlavor(DishDTO source) {
        DishPO dishPO = DishMapper.INSTANCE.DTOConvertPO(source);
        //向菜品表插入1条数据
        dishRepository.insert(dishPO);
        Long dishId = dishPO.getId();
        //向口味表插入n条数据
        List<DishFlavorPO> flavors = source.getFlavors();
        if(CollUtil.isNotEmpty(flavors)){
            flavors.forEach(s->s.setDishId(dishId));
            //向口味表中批量插入数据
            dishFlavorService.insertBatch(flavors);
        }
        redisTemplate.delete(RedisDataConstant.DISH_CACHE + dishPO.getCategoryId());
        return true;
    }

    /**
     * 菜品分页查询
     * @param source
     * @return
     */
    @Override
    public PageResult page(DishPageQueryDTO source) {
        Page<DishVO> page = new Page<>(source.getPage(),source.getPageSize());
        dishRepository.page(page,source);
        return new PageResult(page.getTotal(), page.getRecords());
    }

    /**
     * 菜品批量删除
     * @param ids
     */
    @Transactional
    @Override
    @CacheEvict(cacheNames = "cache:dish",allEntries = true)
    public void delete(List<Long> ids) {
        //是否是启售中的商品
        long count = dishRepository.selectBatchIds(ids).stream().filter(s -> s.getStatus() > 0).count();//过滤出启售的商品数量
        if (count>0){
            throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
        }
        //是否被套餐关联
        count = setmealDishRepository.selectCount(new LambdaQueryWrapper<SetmealDishPO>()
                .in(SetmealDishPO::getDishId,ids));
        if (count>0){
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }
        //删除菜品表中的菜品数据
        dishRepository.deleteBatchIds(ids);
        //删除菜品关联的口味
        dishFlavorService.deleteByDishIdBatch(ids);
        //删除Redis中的数据
    }

    /**
     * 根据id查询菜品
     * @param id
     * @return
     */
    @Override
    @Cacheable(cacheNames = "cache:dish",key = "#id")
    public DishVO getByIdWithFlavor(Long id) {
        //根据id查询菜品数据
        DishPO dishPO = dishRepository.selectById(id);
        if(ObjectUtil.isNull(dishPO)){
            throw new BaseException(MessageConstant.DISH_IS_NOT_EXIST);
        }
        //根据菜品id查询口味数据
        List<DishFlavorPO> byDishId = dishFlavorService.getByDishId(id);
        //将查询到的数据封装到VO
        DishVO dishVO = DishMapper.INSTANCE.POConvertVO(dishPO);
        dishVO.setFlavors(byDishId);
        return dishVO;
    }

    /**
     * 修改菜品
     * @param source
     */
    @Override
    @CacheEvict(cacheNames = "cache:dish",key = "#source.id")
    public void update(DishDTO source) {
        //修改菜品基本信息
        dishRepository.updateById(DishMapper.INSTANCE.DTOConvertPO(source));
        //删除原有的口味数据
        dishFlavorService.deleteByDishIdBatch(Collections.singletonList(source.getId()));
        //重新插入口味数据
        List<DishFlavorPO> flavors = source.getFlavors();
        if(CollUtil.isNotEmpty(flavors)){
            flavors.forEach(s->s.setDishId(source.getId()));
            //向口味表中批量插入数据
            dishFlavorService.insertBatch(flavors);
        }
        redisTemplate.delete(RedisDataConstant.DISH_CACHE + source.getCategoryId());
    }

    /**
     * 条件查询菜品和口味
     * @param categoryId
     * @return
     */
    public List<DishVO> listWithFlavor(Long categoryId) {
        //查询redis中是否存在菜品数据
        List<DishVO> voList = (List<DishVO>) redisTemplate.opsForValue().get(RedisDataConstant.DISH_CACHE + categoryId);
        //如果存在直接返回
        if(CollUtil.isNotEmpty(voList)){
            return voList;
        }
        //如果不存在,查询数据库返回,将查询到的数据放入Redis
        List<DishVO> dishVOList = dishRepository.getDishByCategoryId(categoryId);
        redisTemplate.opsForValue().set(RedisDataConstant.DISH_CACHE + categoryId,dishVOList);
        return dishVOList;
    }

    /**
     * 更新菜品状态
     * @param status
     * @param id
     * @return
     */
    @Override
    @Cacheable(cacheNames = "cache:dish",key = "#id")
    public Boolean updateStatus(Integer status, Long id) {
        DishPO dishPO = dishRepository.selectById(id);
        dishPO.setStatus(status);
        redisTemplate.delete(RedisDataConstant.DISH_CACHE + dishPO.getCategoryId());
        return dishRepository.updateById(dishPO)>0;
    }

    /**
     * 根据分类id查询菜品
     * @param categoryId
     * @return
     */
    @Override
    public List<DishPO> selectByCategoryId(Long categoryId) {
        return dishRepository.selectList(new LambdaQueryWrapper<DishPO>()
                .eq(DishPO::getCategoryId,categoryId)
                .eq(DishPO::getStatus,"1"));
    }

    /**
     * 根据套餐id联立套餐菜品表查询菜品数据
     * @param setmealId
     * @return
     */
    @Override
    public List<DishPO> selectBySetmealId(Long setmealId) {
        return dishRepository.selectBySetmealId(setmealId);
    }
}
